package com.qigao.mall.web.config;

import com.qigao.mall.api.DataStoreService;
import com.qigao.mall.web.except.SsoShiroExceptionHandler;
import com.qigao.mall.web.filter.SsoTokenFilter;
import com.qigao.mall.web.shiro.MyCredentialsMatcher;
import com.qigao.mall.web.shiro.MyShiroRealm;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerExceptionResolver;

import javax.annotation.Resource;
import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author luiz
 */
@Configuration
public class ShiroConfig {
    private static Logger logger = LoggerFactory.getLogger(ShiroConfig.class);
    /**
     * 应用名称
     */
    @Value("${spring.application.name}")
    private String appCode;

    @Resource
    private DataStoreService dataStoreService;


    @Bean("ssoHandlerExceptionResolver")
    public HandlerExceptionResolver handlerExceptionResolver() {
        return new SsoShiroExceptionHandler();
    }

    /**
     * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
     * 配置以下两个bean(DefaultAdvisorAutoProxyCreator和AuthorizationAttributeSourceAdvisor)即可实现此功能
     *
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    /**
     * 开启aop注解支持
     *
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") org.apache.shiro.mgt.SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    /**
     * 保证实现了Shiro内部lifecycle函数的bean执行
     *
     * @return
     */
    @Bean(name = "lifecycleBeanPostProcessor")
    public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * 配置自定义的权限登录器
     *
     * @param matcher
     * @return
     */
    @Bean(name = "authRealm")
    public MyShiroRealm myShiroRealm(@Qualifier("credentialsMatcher") CredentialsMatcher matcher) {
        MyShiroRealm myShiroRealm = new MyShiroRealm();
        myShiroRealm.setCredentialsMatcher(matcher);
        //用户授权/认证信息Cache, 采用EhCache 缓存
        // myShiroRealm.setCacheManager(getEhCacheManager());
        return myShiroRealm;
    }

    /**
     * 配置核心安全事务管理器
     *
     * @param authRealm
     * @return
     */
    @Bean(name = "securityManager")
    public org.apache.shiro.mgt.SecurityManager securityManager(@Qualifier("authRealm") MyShiroRealm authRealm) {
        org.apache.shiro.web.mgt.DefaultWebSecurityManager manager = new org.apache.shiro.web.mgt.DefaultWebSecurityManager();
        manager.setRealm(authRealm);
        return manager;
    }

    /**
     * 配置自定义的密码比较器
     *
     * @return
     */
    @Bean(name = "credentialsMatcher")
    public CredentialsMatcher credentialsMatcher() {
        return new MyCredentialsMatcher();
       /* HashedCredentialsMatcher hashedCredentialsMatcher=new  HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        return hashedCredentialsMatcher;*/
    }

    /**
     * 配置shiro的过滤器工厂类
     *
     * @param manager
     * @return (name = " shiroFilter ")
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") org.apache.shiro.mgt.SecurityManager manager, ShiroProperties sp) {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        bean.setSecurityManager(manager);
        //配置登录的url和登录成功的url和无权限 loginUrl不填默认跳转到loginUrl
        //bean.setUnauthorizedUrl(ssoServer);
        //bean.setLoginUrl(ssoServer);
        //自定义拦截器
        Map<String, Filter> filtersMap = new LinkedHashMap<String, Filter>();
        //控制未登录返回 authc必填
        filtersMap.put("authc", new SsoTokenFilter(dataStoreService));
        bean.setFilters(filtersMap);
        //配置访问权限
        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        filterChainDefinitionMap.put("/logout", "anon");
        if (sp.getShiroAnon() != null) {
            String[] anonArray = sp.getShiroAnon().split(",");
            for (String annoUrl : anonArray) {
                logger.warn("Configure [{}] as anon", annoUrl);
                filterChainDefinitionMap.put(annoUrl, "anon");
            }
        }
        if (sp.getShiroAuth() != null) {
            String[] authArray = sp.getShiroAuth().split(",");
            for (String authUrl : authArray) {
                logger.warn("Configure [{}] as auth", authUrl);
                filterChainDefinitionMap.put(authUrl, "authc");
            }
        }
        bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return bean;
    }

    /**
     * 配置shiro缓存
     * @return
     @Bean public EhCacheManager getEhCacheManager() {
     EhCacheManager em = new EhCacheManager();
     em.setCacheManagerConfigFile("classpath:ehcache/ehcache-shiro.xml");
     return em;
     }*/

    /**
     * 开启shiro注解
     *
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(@Qualifier("securityManager") org.apache.shiro.mgt.SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
        aasa.setSecurityManager(securityManager);
        return aasa;
    }
}
